package com.ruijie.camerax

import android.Manifest
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.ImageFormat
import android.graphics.SurfaceTexture
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.util.Size
import android.view.Surface
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import com.google.common.util.concurrent.ListenableFuture
import com.ruijie.camerax.databinding.ActivityRecoderBinding
import com.ruijie.camerax.media.*
import java.lang.ref.WeakReference
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

class RecorderActivity : AppCompatActivity() {

    companion object {
        private const val RATIO_4_3_VALUE = 4.0 / 3.0
        private const val RATIO_16_9_VALUE = 16.0 / 9.0
        private const val TAG = "RecorderActivity"
        private val REQUIRED_PERMISSIONS =
            arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)
    }

    private lateinit var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>
    private lateinit var _binding: ActivityRecoderBinding

    private var cameraProvider: ProcessCameraProvider? = null
    private lateinit var cameraSelector: CameraSelector


    private lateinit var preview: Preview

    //    private val mPreviewSize = Size(1080, 1440)
    private val mPreviewSize = Size(1080, 1920)
//    private lateinit var mPreviewSize: Size


    private var mEncoder: VideoEncoder? = null

    private var mDecoder: VideoDecoder? = null

    private lateinit var imageAnalysis: ImageAnalysis

    private lateinit var registerForActivityResult: ActivityResultLauncher<Array<String>>


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        Log.d(TAG, "onCreate : ${Resources.getSystem().displayMetrics.widthPixels} ")

        _binding = ActivityRecoderBinding.inflate(layoutInflater)
        setContentView(_binding.root)
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        registerForActivityResult =
            registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { results ->
                val allPermissionGranted = results.all { it.value }
                if (allPermissionGranted) {
                    startCamera()
                }
            }
        registerForActivityResult.launch(REQUIRED_PERMISSIONS)
        _binding.apply {
            surfaceDecoder.surfaceTextureListener = object : SimpleTextureListener() {
                override fun onSurfaceTextureAvailable(
                    surface: SurfaceTexture,
                    width: Int,
                    height: Int
                ) {
                    Log.d(TAG, "onSurfaceTextureAvailable : ")
                }

                override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
                    Log.d(TAG, "onSurfaceTextureDestroyed : ")
                    releaseRecorder()
                    return true
                }
            }

            btnStart.setOnClickListener {
                btnStart.toggle()
                if (btnStart.isChecked) {
                    startRecorder()
                } else {
                    stopRecorder()
                }
            }
        }
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        Log.d(TAG, "onConfigurationChanged : ${newConfig.orientation}")
    }

    private fun startCamera() {
        val manager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
        val cameraId = manager.cameraIdList[0]
//        val cameraCharacteristics = manager.getCameraCharacteristics(cameraId)

//        val map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)

//        val outputSizes = map?.getOutputSizes(ImageFormat.YUV_420_888)
////        mPreviewSize = chooseSize(outputSizes)
//        outputSizes?.forEach {
//            Log.d(TAG, "startCamera : $it")
//        }


        cameraProviderFuture.addListener({
            cameraProvider = cameraProviderFuture.get()
            bindPreview(cameraProvider)
        }, ContextCompat.getMainExecutor(this))
    }


    private fun bindPreview(cameraProvider: ProcessCameraProvider?) {
        cameraProvider?.apply {

            val rotation = _binding.previewV.display.rotation
            val metrics = Resources.getSystem().displayMetrics
            Log.d(TAG, "Screen metrics: ${metrics.widthPixels} x ${metrics.heightPixels}")
            val screenAspectRatio = aspectRatio(metrics.widthPixels, metrics.heightPixels)

            preview = Preview.Builder()
                .setTargetResolution(mPreviewSize)
//                .setTargetAspectRatio(screenAspectRatio)
                .setTargetRotation(rotation)
                .build()

            Log.d(
                TAG,
                "Preview aspect ratio: $screenAspectRatio ; rotation = $rotation ; "
            )

            preview.setSurfaceProvider(_binding.previewV.surfaceProvider)

            imageAnalysis = ImageAnalysis.Builder()
                .setTargetResolution(mPreviewSize)
//                .setTargetAspectRatio(screenAspectRatio)
                .setTargetRotation(rotation)
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build()

            imageAnalysis.setAnalyzer(Executors.newSingleThreadExecutor()) { image ->
                if (!hasSetup.get()) {
                    myHandler.obtainMessage(1, image.width, image.height).sendToTarget()
                }
                if (hasSetup.get() && startRecorder.get()) {
                    //获取一个用于填充yuv数据的缓存
                    mEncoder?.pollYUVBuffer()?.let {
                        Image2yuvUtils.image2NV21(image, it)
                        mEncoder!!.offerYUVBuffer(it)
                    }
                }
                image.close()
            }

            cameraSelector = CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build()

            unbindAll()

            bindToLifecycle(
                this@RecorderActivity,
                cameraSelector,
                preview, imageAnalysis
            )
        }
    }


    private fun aspectRatio(width: Int, height: Int): Int {
        val previewRatio = max(width, height).toDouble() / min(width, height)
        if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
            return AspectRatio.RATIO_4_3
        }
        return AspectRatio.RATIO_16_9
    }

    override fun onPause() {
        super.onPause()
        stopRecorder()
    }


    override fun onDestroy() {
        super.onDestroy()
        releaseRecorder()

    }

    private val hasSetup = AtomicBoolean(false)
    private val startRecorder = AtomicBoolean(false)


    private fun setupCodec(width: Int, height: Int) {
        val rotation = 90
        mEncoder = VideoEncoder().also {
            it.init(width, height, rotation, false)
        }
//
        mDecoder = VideoDecoder()
        val surface = Surface(_binding.surfaceDecoder.surfaceTexture)
        mDecoder?.init(surface, width, height, rotation)
        mDecoder?.setEncoder(mEncoder)
        hasSetup.set(true)
    }

    private fun startRecorder() {
        mEncoder?.start()
        mDecoder?.start()
        startRecorder.set(true)
    }

    private fun stopRecorder() {
        mEncoder?.stop()
        mDecoder?.stop()
        startRecorder.set(false)
    }

    private fun releaseRecorder() {
        mEncoder?.release()
        mDecoder?.release()
    }

    private val myHandler = MainHandler(this)

    class MainHandler(activity: RecorderActivity) : Handler(Looper.getMainLooper()) {
        private val weakReference = WeakReference(activity)
        override fun handleMessage(msg: Message) {

            when (msg.what) {
                1 -> {
                    weakReference.get()?.setupCodec(msg.arg1, msg.arg2)
                }
                2 -> {

                }
            }
        }
    }
}
